package com.yangchuang.openpicture.util;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.Objects;

/**
 * 上海时区(Asia/Shanghai)时间工具类
 * 提供当前时间获取、时间比较、格式转换、时间差计算等功能
 */
public final class ShanghaiTimeUtils {

    /**
     * 上海时区 (固定为Asia/Shanghai)
     */
    public static final ZoneId SHANGHAI_ZONE_ID = ZoneId.of("Asia/Shanghai");

    /**
     * 常用时间格式 - 年月日时分秒 (yyyy-MM-dd HH:mm:ss)
     */
    public static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 年月日格式 (yyyy-MM-dd)
     */
    public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    /**
     * 时分秒格式 (HH:mm:ss)
     */
    public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");

    // 私有构造函数，禁止实例化
    private ShanghaiTimeUtils() {
        throw new AssertionError("工具类不允许实例化");
    }

    // -------------------------- 获取当前时间 --------------------------

    /**
     * 获取上海时区当前LocalDateTime
     *
     * @return 当前时间（上海时区）
     */
    public static LocalDateTime getCurrentLocalDateTime() {
        return LocalDateTime.now(SHANGHAI_ZONE_ID);
    }

    /**
     * 获取上海时区当前时间字符串（默认格式：yyyy-MM-dd HH:mm:ss）
     *
     * @return 格式化后的当前时间字符串
     */
    public static String getCurrentTimeStr() {
        return format(getCurrentLocalDateTime(), DEFAULT_FORMATTER);
    }

    /**
     * 获取上海时区当前时间字符串（自定义格式）
     *
     * @param formatter 时间格式器
     * @return 格式化后的当前时间字符串
     */
    public static String getCurrentTimeStr(DateTimeFormatter formatter) {
        return format(getCurrentLocalDateTime(), formatter);
    }

    /**
     * 获取上海时区当前时间戳（毫秒级）
     *
     * @return 从1970-01-01 00:00:00 UTC开始的毫秒数
     */
    public static long getCurrentTimestamp() {
        return ZonedDateTime.now(SHANGHAI_ZONE_ID).toInstant().toEpochMilli();
    }

    // -------------------------- 时间格式化 --------------------------

    /**
     * 将LocalDateTime格式化为字符串（默认格式）
     *
     * @param dateTime 要格式化的时间
     * @return 格式化后的字符串
     */
    public static String format(LocalDateTime dateTime) {
        return format(dateTime, DEFAULT_FORMATTER);
    }

    /**
     * 将LocalDateTime格式化为字符串（自定义格式）
     *
     * @param dateTime  要格式化的时间
     * @param formatter 时间格式器
     * @return 格式化后的字符串
     */
    public static String format(LocalDateTime dateTime, DateTimeFormatter formatter) {
        if (dateTime == null || formatter == null) {
            return null;
        }
        return dateTime.format(formatter);
    }

    // -------------------------- 字符串解析为时间 --------------------------

    /**
     * 将字符串解析为LocalDateTime（默认格式：yyyy-MM-dd HH:mm:ss）
     *
     * @param timeStr 时间字符串
     * @return 解析后的LocalDateTime（上海时区上下文）
     * @throws DateTimeParseException 格式不匹配时抛出
     */
    public static LocalDateTime parse(String timeStr) {
        return parse(timeStr, DEFAULT_FORMATTER);
    }

    /**
     * 将字符串解析为LocalDateTime（自定义格式）
     *
     * @param timeStr   时间字符串
     * @param formatter 时间格式器
     * @return 解析后的LocalDateTime（上海时区上下文）
     * @throws DateTimeParseException 格式不匹配时抛出
     */
    public static LocalDateTime parse(String timeStr, DateTimeFormatter formatter) {
        if (timeStr == null || timeStr.trim().isEmpty() || formatter == null) {
            return null;
        }
        return LocalDateTime.parse(timeStr, formatter);
    }

    // -------------------------- 时间比较 --------------------------

    /**
     * 判断时间A是否在时间B之后
     *
     * @param timeA 时间A
     * @param timeB 时间B
     * @return true：timeA在timeB之后；false：否则（包含null情况）
     */
    public static boolean isAfter(LocalDateTime timeA, LocalDateTime timeB) {
        if (timeA == null || timeB == null) {
            return false;
        }
        return timeA.isAfter(timeB);
    }

    /**
     * 判断时间A字符串是否在时间B字符串之后（默认格式）
     *
     * @param timeStrA 时间A字符串
     * @param timeStrB 时间B字符串
     * @return true：timeA在timeB之后；false：否则（包含解析失败）
     */
    public static boolean isAfter(String timeStrA, String timeStrB) {
        return isAfter(timeStrA, timeStrB, DEFAULT_FORMATTER);
    }

    /**
     * 判断时间A字符串是否在时间B字符串之后（自定义格式）
     *
     * @param timeStrA  时间A字符串
     * @param timeStrB  时间B字符串
     * @param formatter 时间格式器
     * @return true：timeA在timeB之后；false：否则（包含解析失败）
     */
    public static boolean isAfter(String timeStrA, String timeStrB, DateTimeFormatter formatter) {
        try {
            LocalDateTime timeA = parse(timeStrA, formatter);
            LocalDateTime timeB = parse(timeStrB, formatter);
            return isAfter(timeA, timeB);
        } catch (DateTimeParseException e) {
            return false;
        }
    }

    /**
     * 判断时间A是否在时间B之前
     *
     * @param timeA 时间A
     * @param timeB 时间B
     * @return true：timeA在timeB之前；false：否则（包含null情况）
     */
    public static boolean isBefore(LocalDateTime timeA, LocalDateTime timeB) {
        if (timeA == null || timeB == null) {
            return false;
        }
        return timeA.isBefore(timeB);
    }

    /**
     * 判断时间A字符串是否在时间B字符串之前（默认格式）
     *
     * @param timeStrA 时间A字符串
     * @param timeStrB 时间B字符串
     * @return true：timeA在timeB之前；false：否则（包含解析失败）
     */
    public static boolean isBefore(String timeStrA, String timeStrB) {
        return isBefore(timeStrA, timeStrB, DEFAULT_FORMATTER);
    }

    /**
     * 判断时间A字符串是否在时间B字符串之前（自定义格式）
     *
     * @param timeStrA  时间A字符串
     * @param timeStrB  时间B字符串
     * @param formatter 时间格式器
     * @return true：timeA在timeB之前；false：否则（包含解析失败）
     */
    public static boolean isBefore(String timeStrA, String timeStrB, DateTimeFormatter formatter) {
        try {
            LocalDateTime timeA = parse(timeStrA, formatter);
            LocalDateTime timeB = parse(timeStrB, formatter);
            return isBefore(timeA, timeB);
        } catch (DateTimeParseException e) {
            return false;
        }
    }

    /**
     * 判断两个时间是否相等
     *
     * @param timeA 时间A
     * @param timeB 时间B
     * @return true：相等；false：否则
     */
    public static boolean isEqual(LocalDateTime timeA, LocalDateTime timeB) {
        return Objects.equals(timeA, timeB);
    }

    /**
     * 判断两个时间字符串是否相等（默认格式）
     *
     * @param timeStrA 时间A字符串
     * @param timeStrB 时间B字符串
     * @return true：相等；false：否则（包含解析失败）
     */
    public static boolean isEqual(String timeStrA, String timeStrB) {
        return isEqual(timeStrA, timeStrB, DEFAULT_FORMATTER);
    }

    /**
     * 判断两个时间字符串是否相等（自定义格式）
     *
     * @param timeStrA  时间A字符串
     * @param timeStrB  时间B字符串
     * @param formatter 时间格式器
     * @return true：相等；false：否则（包含解析失败）
     */
    public static boolean isEqual(String timeStrA, String timeStrB, DateTimeFormatter formatter) {
        try {
            LocalDateTime timeA = parse(timeStrA, formatter);
            LocalDateTime timeB = parse(timeStrB, formatter);
            return isEqual(timeA, timeB);
        } catch (DateTimeParseException e) {
            return false;
        }
    }

    // -------------------------- 时间差计算 --------------------------

    /**
     * 计算两个时间之间的差值（单位：指定时间单位）
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param unit      时间单位（如ChronoUnit.MINUTES）
     * @return 时间差（endTime - startTime），若参数无效返回0
     */
    public static long between(LocalDateTime startTime, LocalDateTime endTime, ChronoUnit unit) {
        if (startTime == null || endTime == null || unit == null) {
            return 0;
        }
        return unit.between(startTime, endTime);
    }

    /**
     * 计算两个时间字符串之间的差值（默认格式，单位：指定时间单位）
     *
     * @param startStr 开始时间字符串
     * @param endStr   结束时间字符串
     * @param unit     时间单位
     * @return 时间差（endStr - startStr），若解析失败返回0
     */
    public static long between(String startStr, String endStr, ChronoUnit unit) {
        return between(startStr, endStr, DEFAULT_FORMATTER, unit);
    }

    /**
     * 计算两个时间字符串之间的差值（自定义格式，单位：指定时间单位）
     *
     * @param startStr  开始时间字符串
     * @param endStr    结束时间字符串
     * @param formatter 时间格式器
     * @param unit      时间单位
     * @return 时间差（endStr - startStr），若解析失败返回0
     */
    public static long between(String startStr, String endStr, DateTimeFormatter formatter, ChronoUnit unit) {
        try {
            LocalDateTime startTime = parse(startStr, formatter);
            LocalDateTime endTime = parse(endStr, formatter);
            return between(startTime, endTime, unit);
        } catch (DateTimeParseException e) {
            return 0;
        }
    }

    // -------------------------- 时间加减 --------------------------

    /**
     * 对时间进行加减操作
     *
     * @param time   原始时间
     * @param amount 数量（正数为加，负数为减）
     * @param unit   时间单位
     * @return 计算后的时间，若原始时间为null则返回null
     */
    public static LocalDateTime plus(LocalDateTime time, long amount, ChronoUnit unit) {
        if (time == null || unit == null) {
            return null;
        }
        return time.plus(amount, unit);
    }

    /**
     * 对时间字符串进行加减操作（默认格式）
     *
     * @param timeStr 时间字符串
     * @param amount  数量（正数为加，负数为减）
     * @param unit    时间单位
     * @return 计算后的时间字符串，若解析失败返回null
     */
    public static String plus(String timeStr, long amount, ChronoUnit unit) {
        return plus(timeStr, amount, unit, DEFAULT_FORMATTER);
    }

    /**
     * 对时间字符串进行加减操作（自定义格式）
     *
     * @param timeStr   时间字符串
     * @param amount    数量（正数为加，负数为减）
     * @param unit      时间单位
     * @param formatter 时间格式器
     * @return 计算后的时间字符串，若解析失败返回null
     */
    public static String plus(String timeStr, long amount, ChronoUnit unit, DateTimeFormatter formatter) {
        try {
            LocalDateTime time = parse(timeStr, formatter);
            LocalDateTime newTime = plus(time, amount, unit);
            return format(newTime, formatter);
        } catch (DateTimeParseException e) {
            return null;
        }
    }
}
